# Модуль 1. Понятие класса. Инкапсуляция  (4 ак. ч.)

### План

*	Класс и экземпляр класса.
*	Данные экземпляра, методы экземпляра и свойства экземпляра.
*	Понятие атрибута.
*	Практикум: Создание класса и его экземпляров.



## Введение


## Парадигмы программирования

![](img/paradigm.png)

* структурное
* функциональное
* объектно-ориентированное



<details>
<summary>подробнее про парадигмы</summary>

Функциональное программирование открыто в 1936 году, когда Чёрч придумал лямбда-исчисление. 

Первый функциональный язык LISP был создан в 1958 году Джоном МакКарти.

В 1968 году Дейкстра понял, что `goto` – это зло, и программы должны строиться из трёх базовых структур: 

> последовательности, ветвления и цикла

С этого момента появился термин структурное программирования.

Этап активного развития алгоритмических языков. 

До этого языки машиные коды, перфокарты и языки ассемблера,

Концепция ООП зародилась в 1960-x гг. когда. 

Каждая из этих парадигм убирает возможности у программиста, а не добавляет.

Они говорят нам скорее, что нам не нужно делать, чем то, что нам нужно делать.


Но стоит отметить, что вплоть до начала 1990-х программисты могли свободно обходиться без ООП, пока оно не стало доминирующим направлением и внедрено в самый популярный (на тот момент) язык программирования С++. 

Так что же это такое и почему сейчас знать ООП должен каждый, уважающий себя, начинающий программист?

Для нас важно вот что: речь будет идти не просто о классах и объектах, а о том, как концепция классов и объектов реализуется в языке Python. 

Почему это важно? 

Важно потому, что сама по себе тема ООП и, более конкретно, классов и объектов, обычно достаточно сложна для понимания даже для тех, кто имеет опыт программирования. 

А в случае с языком Python проблемы, скорее всего, возникнут не только у новичков, но и у программистов, знакомых с методами ООП на примере таких языков, как C++, Java или С#.

С другой стороны ООП в Python достаточно проста понимания.

Для тех, кто знаком с другими объектно-ориентированными языками: в `Python` класс сам является объектом. 

Это  обстоятельство имеет весьма далеко идущие последствия.

Более того, как мы уже знаем, переменные в `Python` не объявляются, а вводятся в программу путем присваивания значения. 

Это же правило остается справедливым при работе с классами и объектами. 

Отсюда получается, что процедура объявления полей, стандартная для многих языков программирования, в `Python` просто теряет смысл. 

Аналогично, многие привычные (по языкам программирования С++, Java и С#) в ООП моменты окажутся чуждыми для языка `Python`. 

Короче говоря, в магии и экзотике недостатка не будет.

</details> 


<details>
<summary>есть ли языки без ООП ?</summary>
🔹 CИ (без плюсов)

🔹 Pascal

🔹 Fortran

🔹 Cobol

🔹 Ассемблер

🔹 Rust

🔹 VBS
</details> 




![](img/oop-2.jpg)


Чтобы понять ООП иногда требуется провести параллели с окружающим миром 

![](img/oop-3.jpg)


<details>
<summary>Что такое ООП</summary>
Что такое ООП? Это такой стиль написания программы, при котором её отдельные компоненты представляются нам объектами из окружающего нас мира.

Самым удачным примером является реализация знакомой всем видеоигры, где волк ловит яйца. В этой игре сущностей, которыми приходится оперировать всего несколько:

🔹 Волк

🔹 Яйцо

🔹 Стойка, по которой катится яйцо


Представьте, что с точки зрения написания программы каждая из этих сущностей обладает своим "чертежом", по которому она создается. 

Чертеж вы создаёте единожды для каждой сущности, а дальше клепаете по ним столько объектов, сколько вам угодно!

Те, кто не знаком с искусством разработки могут удивиться, но во многом именно так и создаются современные видеоигры!
</details>



### 1. Что такое ООП?

![](img/oop-1.png)

- Программирование, построенное на классах
- Инструмент стратегического планирования
- Программная единица пакетирования логики и данных

<details>
<summary>...</summary>

* ООП — эффективный способ программирования, который предусматривает разложение кода на составляющие с целью минимизации избыточности и написания новых программ путем настройки существующего кода, а не его изменения на месте

* ООП — это одна из парадигм разработки, подразумевающая организацию программного кода, ориентируясь на данные и объекты, а не на функции и логические структуры.

* ООП — методология или стиль программирования на основе описания типов/моделей предметной области и их взаимодействия, представленных порождением из прототипов или как экземпляры классов, которые образуют иерархию наследования
</details>


![](img/oop-3.png)



### ОО ДИЗАЙН 

![](img/oo-design.png)

### ПРИНЦИПЫ ДЯДИ БОБА

![](img/bob.png)

### ОО-паттерны
![](img/oo-patterns.png)

### Банда 4-x

![](img/banda-4.png)


Обучение тому, как задействовать классы, требует времени. 

На практике ООП также влечет за собой значительную
работу по проектированию, чтобы получить все преимущества от многократного использования кода классов. 

С этой целью программисты начали каталогизировать распространенные структуры ООП, известные как паттерны проектирования, которые призваны помочь в решении проблем, возникающих при проектировании. 

Однако действительный код, который вы пишете с применением ООП в Python, настолько прост, что сам по себе он не будет дополнительным препятствием ОО-программирования.

* Linux написана на Си(без классов)
* интепретатор Питона (на СИ, минимим классов)
* Iot - без классов (СИ, ассемблеры),
* микроконтроллеры

### Пример-анти-пример 

вспомним курс `Python-1`

```python
печать = print
print = 123
печать (print)
```

> в нем мы переназначили встроенную функцию print, а потом еще и переопределили её. Питон это позволяет!

А теперь еще круче ... 

```python
n1 = int(10)
n2 = 20

print(type(n1), )
```

#### Что делает функция type?

> <class 'int'>

давайте провалимся как в определение ф-ции или класса int

![](img/__add__.png)

Что такое класс int?

#### А теперь немного магии

```python
n1 = 10
n2 = 20
print(n1 + n2)
print(n1.__add__(n2))
```


```python
class int(int):

    def __add__(n, value):
        return n * value


n1 = int(10)
n2 = 5

print(n1 + n2) # 50
```
> 50 

_Что вообще происходит ?_

> ###  Можно ли в Питоне складывать числа со строками?

```
ответ джуна, ответ синьора_
```

> ###  Чем функция отличается от метода? (print, int, string ...)

```python
set_a = {1, 2, 3, 4, 5}
set_b = {5, 6, 7}

print(set_a & set_b)
print(set_a.intersection(set_b))
print(set_a.__and__(set_b))
```



```python
x = 1.5
print(x.as_integer_ratio())

y = 15

print(y.bit_count())
print(type(y))

x = bin(y)
```



```python
print(type(type))

s = 'ABCDE'
res = s.lower
print(1,res) # <built-in method lower of str object at 0x000001DC84214AF0>
res1 = s.lower()
print(2,res1) # 10

Без скобок вы получаете значение.

Со скобками - результат работы функции.

```
Об этом далее ...  

## 1 задача - научиться наследоваться от встроенных классов `Python` и изменять их
## 2 задача - создавать свои пользовательские типы данных на основе классов
